import { httpFile } from './http.js'
import { updateDb, addDb, findDb, deleteDb } from './indexDB.js'

// 文件上传
const common = {}
export const uploadFileHttp = (fileList, config, oldPrg = 0) => {
    let nextprg = 100 - oldPrg
    let fileLeg = fileList.length
    let cutPrg = nextprg / fileLeg
    common['uploadFileList'+config.id] = []
    common['successLeg'+config.id] = 0
    common['errorNum'+config.id] = 0
    common['prg'+config.id] = []
    common['oldPrg'+config.id] = oldPrg
    common['nowPrg'+config.id] = 0
    fileList.forEach(item => {
        const formData = new FormData()
        formData.append('id', config.id)
        for (let key in item) {
            !['status'].includes(key) && formData.append(key, item[key])
        }
        for (let key in config.option.body) {
            formData.append(key, config.option.body[key])
        }
        common['uploadFileList'+config.id].push(formData)
    })
    // 剩余代码基本在此  一次发布6个请求 成功或失败一个就再发一个 失败的要将失败的加入到栈后
    let t = fileLeg > 6 ? 6 : fileLeg
    for(let i = 0;  i < t; i++){
        httpUploadFile(config, common['uploadFileList'+config.id][0], cutPrg, fileLeg, fileList)
        common['uploadFileList'+config.id].shift()
    }
}
// 发送请求
const httpUploadFile = (config, formData, cutPrg, fileLeg, fileList) => {
    if(!formData) return
    let chunkIndex = Number(formData.get('chunkIndex'))
    httpFile(config.option.url, formData, config.option.headers, 
    prg => {
        common['prg'+config.id][chunkIndex] = prg * cutPrg / 100
        let tota = common['prg'+config.id].reduce((accumulator, currentValue) => accumulator + currentValue, 0)
        if (common['nowPrg'+config.id] > tota) tota = common['nowPrg'+config.id]
        else common['nowPrg'+config.id] = tota
        let nowPrg = tota + common['oldPrg'+config.id]
        nowPrg = nowPrg > 100 ? 100 : nowPrg
        config.progress(nowPrg.toFixed(2)) // 将上传进度返出去
    }, 
    secc => {
        httpUploadSucc(config, formData, cutPrg, fileLeg, fileList, chunkIndex)
    }, 
    fail => {
        common['prg'+config.id][chunkIndex] = 0 // 失败将进度会退
        httpUploadFail(config, formData, cutPrg, fileLeg, fileList)
    })
}
// 切片请求成功
const httpUploadSucc = async(config, formData, cutPrg, fileLeg, fileList, chunkIndex) => {
    common['successLeg'+config.id]++
    fileList.forEach(item => { if (item.chunkIndex === chunkIndex) item.status = 1 })
    if (common['uploadFileList'+config.id].length) {
        await updateDb({ id: config.id, files: fileList}) // 去更新indexdb 将状态改为已上传
        httpUploadFile(config, common['uploadFileList'+config.id][0], cutPrg, fileLeg, fileList) // 上传成功马上发起下一次请求（如果栈中还有未上传的）
        common['uploadFileList'+config.id].shift()
    }
    if (common['successLeg'+config.id] === fileLeg ) {
        await deleteDb(config.id) // 将成功的这条数据删除
        config.success('上传完成') // 全部切片上传完成
        //  清除闭包数据
        delete common['uploadFileList'+config.id] 
        delete common['successLeg'+config.id]
        delete common['errorNum'+config.id]
        delete common['prg'+config.id] 
        delete common['oldPrg'+config.id]
        delete common['nowPrg'+config.id]
    }
}
// 切片请求失败
const httpUploadFail = (config, formData, cutPrg, fileLeg, fileList) => {
    common['uploadFileList'+config.id].push(formData)  // 将失败数据加入到栈的末尾
    common['successLeg'+config.id]--
    common['errorNum'+config.id]++
    if (common['errorNum'+config.id] > 6) {
        // 如果有20个失败就暂停上传
        if (common['errorNum'+config.id] === 20) {
            config.fail("上传失败，稍后再试")
            return
        } else if (common['errorNum'+config.id] > 20 ) {
            return
        } else {
            // 如果失败的个数大于6个 放慢发起请求速度
            let time = Math.ceil(common['errorNum'+config.id]/6) *500
            setTimeout(() => {
                httpUploadFile(config, common['uploadFileList'+config.id][0], cutPrg, fileLeg, fileList) // 发起下一个上传切片请求
                common['uploadFileList'+config.id].shift()
            }, time)
        }
    } else {
        httpUploadFile(config, common['uploadFileList'+config.id][0], cutPrg, fileLeg, fileList) // 发起下一个上传切片请求
        common['uploadFileList'+config.id].shift()
    }

}
// 数据存到indexdb
export const saveIndexDb = async(fileList, config) => {
    let dbFile = fileList.map(item => {
        return { status: 0, ...item } // status 0: 未上传  1:已上传
    })
    try {
        let list = await findDb(config.id)
        if (list) await updateDb({ id: config.id, files: dbFile})
        else await addDb({ id: config.id, files: dbFile})
    } catch (error) {
        console.error(error);
    }
}
// 分割文件 size 默认5M
export const cutFile = (file, size = 1024 * 1024 * 10) => {
    let current = 0; //这个文件切片之后下一个切片的大小
    let i = 1
    const totalChunks = Math.ceil(file.size / size); // 计算总的切片数量
    const res = []; //切片结果数组
    //循环地去切片，当前所有切过的文件大小大于总大小就跳出循环，说明已经切完了
    while (current < file.size) {
        res.push({
            file: file.slice(current, current + size),
            chunkIndex: i, 
            totalChunks: totalChunks, 
            fileName: file.name
        });
        current += size;
        i++
    }
    return res;
}